﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.Geodatabase;

namespace CanSWAT.ArcSWAT.Soil
{
    /// <summary>
    /// soil components
    /// </summary>
    class SoilComponent
    {
        public SoilComponent(IRow r)
        {
            _id = ArcGISRow.ReadString(r, "POLY_ID");
            _soil_id = ArcGISRow.ReadString(r, "SOIL_KEY");
            _percent = ArcGISRow.ReadDouble(r, "PERCENT") / 100.0; //convert to percent
        }

        public SoilComponent(string soilID, double percent)
        {
            _soil_id = soilID;
            _percent = percent;
        }

        private string _id = "";
        private string _soil_id = "";
        private double _percent = 1.0;

        private List<SoilDeriv> _derivs = new List<SoilDeriv>();

        public List<SoilDeriv> Derivs
        {
            get { return _derivs; }
            set { _derivs = value; }
        }

        public string ID { get { return _id; } }
        public string SOIL_ID { get { return _soil_id; } }
        public double Percent { get { return _percent; } }
        public override string ToString()
        {
            return _soil_id + "_" + _percent.ToString();
        }

        /// <summary>
        /// Output as string in user soil table format
        /// </summary>
        /// <returns></returns>
        public string ToUserSoilTableString(ArcSWATVersion version)
        {
            StringBuilder sb = new StringBuilder();
            StringBuilder sb_Ca = new StringBuilder();
            StringBuilder sb_PH = new StringBuilder();
            for (int i = 0; i < 10;i++ )
            {
                if (sb.Length > 0) sb.Append(",");
                if (i < _derivs.Count)//has derivs
                {
                    sb.Append(_derivs[i].ToUserSoilTableString());
                    if (version == ArcSWATVersion.A2012)
                    {
                        sb_Ca.Append("," + _derivs[i].CalciumCarbonate.ToString());
                        sb_PH.Append("," + _derivs[i].PH.ToString());
                    }
                }
                else //just add default 0
                {
                    sb.Append(string.Format("{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}", 0));
                    if (version == ArcSWATVersion.A2012)
                    {
                        sb_Ca.Append(",0");
                        sb_PH.Append(",0");
                    }
                }

            }
            return string.Format("{3},{3},{0},{3},0,{1},{3},2000,0.5,0.5,{3},{2}{4}{5}", SOIL_ID, _derivs.Count, sb, "", sb_Ca, sb_PH);
        }

        public override bool Equals(object obj)
        {
            if (obj == null) return false;

            SoilComponent comp = obj as SoilComponent;
            if (comp == null) return false;

            return this.SOIL_ID.Equals(comp.SOIL_ID);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Merge with other soil component to get a new component
        /// </summary>
        /// <param name="comp"></param>
        /// <returns></returns>
        public SoilComponent Merge(SoilComponent comp)
        {
            if (comp == null) return this;
            if (this.Equals(comp)) return this;

            //calculate new soil deriv
            SoilComponent longComp = this;
            SoilComponent shortComp = comp;
            double longPercent = Percent;
            double shortPercent = comp.Percent;
            if (this.Derivs.Count < comp.Derivs.Count)
            {
                longComp = comp;
                shortComp = this;

                longPercent = comp.Percent;
                shortPercent = Percent;
            }

            List<SoilDeriv> newMergedDerivs = new List<SoilDeriv>();
            for (int i = 0; i < longComp.Derivs.Count; i++)
            {
                SoilDeriv driv = longComp.Derivs[i];

                SoilDeriv newShortDriv = null;
                foreach (SoilDeriv shortDriv in shortComp.Derivs)
                {
                    SoilDeriv childShortDriv = shortDriv.Clone(driv.Depth, driv.DepthBottom);
                    if (childShortDriv == null) continue;

                    if (newShortDriv == null) newShortDriv = childShortDriv;
                    else newShortDriv = newShortDriv.Connect(childShortDriv);
                }

                newMergedDerivs.Add(driv.Merge(longPercent, newShortDriv, shortPercent));
            }

            //creat new merged soil component
            string newSoilID = string.Format("{0}{1}-{2}{3}",
                SOIL_ID, Percent, comp.SOIL_ID, comp.Percent);
            SoilComponent newComp = new SoilComponent(newSoilID, Percent + comp.Percent);
            newComp.Derivs = newMergedDerivs;

            return newComp;
        }
    }
}
